﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace QD.Tools
{
    public static class LinqHelper
    {
        //public static Expression<Func<T, bool>> True<T>() { return f => true; }
        //public static Expression<Func<T, bool>> False<T>() { return f => false; }

        /// <summary>
        /// 合并两个Linq表达式，注意在引用时，必须在where条件后加上Compile()，如db.Program.Where(predicate.Compile()).OrderBy(p => p.ProName).ToList();
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expr1"></param>
        /// <param name="expr2"></param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
                                                            Expression<Func<T, bool>> expr2)
        {
            if (expr1 == null && expr2 == null)
            {
                return null;
            }
            else if (expr1 != null && expr2 == null)
            {
                return expr1;
            }
            else if (expr1 == null && expr2 != null)
            {
                return expr2;
            }
            else
            {
                var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
                return Expression.Lambda<Func<T, bool>>
                      (Expression.Or(expr1.Body, invokedExpr), expr1.Parameters);
            }
        }

        /// <summary>
        /// 合并两个Linq表达式，注意在引用时，必须在where条件后加上Compile()，如db.Program.Where(predicate.Compile()).OrderBy(p => p.ProName).ToList();
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expr1"></param>
        /// <param name="expr2"></param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
                                                             Expression<Func<T, bool>> expr2)
        {
            if (expr1 == null && expr2 == null)
            {
                return null;
            }
            else if (expr1 != null && expr2 == null)
            {
                return expr1;
            }
            else if (expr1 == null && expr2 != null)
            {
                return expr2;
            }
            else
            {
                var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
                return Expression.Lambda<Func<T, bool>>
                      (Expression.And(expr1.Body, invokedExpr), expr1.Parameters);
            }
        }
    }
}
